package com.example.exceldemo.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.example.exceldemo.entity.Device;
import com.example.exceldemo.entity.DeviceSimple;
import com.example.exceldemo.entity.Use;
import com.example.exceldemo.entity.UserRecord;
import com.example.exceldemo.exception.ServiceException;
import com.example.exceldemo.listener.DeviceSimpleDataListener;
import com.example.exceldemo.listener.DynamicEasyExcelListener;
import com.example.exceldemo.listener.UseDataListener;
import com.example.exceldemo.service.ImportExcelService;
import com.example.exceldemo.utils.EasyPoiUtil;
import com.example.exceldemo.utils.PoiUtils;
import com.example.exceldemo.utils.easy.ExcelUtils;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.rmi.ServerException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description
 * @Author xiaohuang
 * @Date 2025/2/18
 */
@Slf4j
@Service
public class ImportExcelServiceImpl implements ImportExcelService {
    /**
     * easyExcel简单导入
     *
     * @param file
     */
    @Override
    public void importExcel(MultipartFile file) {
        try (InputStream inputStream = file.getInputStream()) {
            List<DeviceSimple> deviceSimpleList = ExcelUtils.simpImport(inputStream, DeviceSimple.class, 2, null);
            if (!CollectionUtils.isEmpty(deviceSimpleList)) {
                for (DeviceSimple deviceSimple : deviceSimpleList) {
                    log.info("deviceSimple:{}", deviceSimple);
                }
            }
        } catch (IOException e) {
            throw new ServiceException("读取文件异常：", e);
        }
    }

    /**
     * 处理包含多个Sheet的Excel文件，每个Sheet格式简单
     * 该方法首先将文件内容缓存到字节数组，然后预读取Sheet信息，最后逐个处理每个Sheet的数据
     *
     * @param file 上传的Excel文件
     */
    @Override
    public void manyEasySheet(MultipartFile file) {
        try {
            // 1. 将文件内容缓存到字节数组（解决流重复使用问题）
            byte[] fileBytes = file.getBytes();
            // 2. 预读取Sheet信息（使用独立的流）
            List<String> sheetNames = PoiUtils.getSheetNames(fileBytes);
            // 3. 使用新的流处理实际数据读取
            processExcelSheets(fileBytes, sheetNames);
        } catch (IOException e) {
            log.error("文件处理失败: {}", e.getMessage(), e);
            throw new RuntimeException("文件处理失败", e);
        }
    }


    /**
     * 读多个或者全部sheet,这里注意一个sheet不能读取多次，多次读取需要重新读取文件
     * <p>
     * 1. 创建excel对应的实体对象
     * <p>
     * 2. 由于默认异步读取excel，所以需要创建excel一行一行的回调监听器，参照{@link DeviceSimpleDataListener}
     * <p>
     * 3. 直接读即可
     */
    private void processExcelSheets(byte[] fileBytes, List<String> sheetNames) {
        try (InputStream stream = new ByteArrayInputStream(fileBytes);
             ExcelReader excelReader = EasyExcel.read(stream).build()) {
            ArrayList<ReadSheet> readSheets = new ArrayList<>();
            for (int sheetIndex = 0; sheetIndex < sheetNames.size(); sheetIndex++) {
                String sheetName = sheetNames.get(sheetIndex);
                if (sheetName.isEmpty()) {
                    log.warn("跳过无名Sheet: {}", sheetIndex);
                    continue;
                }
                ReadSheet readSheet = createReadSheet(sheetName, sheetIndex);
                if (readSheet != null) {
                    readSheets.add(readSheet);
                }
            }
            //把多个sheet一起传进去，不然有个问题就是03版的excel 会读取多次，浪费性能
            excelReader.read(readSheets);
        } catch (Exception e) {
            throw new RuntimeException("Excel读取失败", e);
        }
    }

    /**
     * 根据Sheet名称创建对应的读取配置
     *
     * @param sheetName  Sheet名称
     * @param sheetIndex Sheet索引
     * @return ReadSheet对象，用于配置Sheet的读取参数，如果Sheet名称未配置则返回null
     */
    private ReadSheet createReadSheet(String sheetName, int sheetIndex) {
        switch (sheetName.toLowerCase()) {
            case "device":
                return EasyExcel.readSheet(sheetIndex)
                        .headRowNumber(2)
                        .head(DeviceSimple.class)
                        .registerReadListener(new DeviceSimpleDataListener())
                        .build();
            case "use":
                return EasyExcel.readSheet(sheetIndex)
                        .headRowNumber(1)
                        .head(Use.class)
                        .registerReadListener(new UseDataListener())
                        .build();
            default:
                log.info("跳过未配置的Sheet: {}", sheetName);
                return null;
        }
    }

    /**
     * 使用easypoi库进行简单的Excel文件导入
     *
     * @param file 上传的Excel文件
     */
    @Override
    public void impEasyPoiExcel(MultipartFile file) {
        ImportParams params = EasyPoiUtil.initParams(1, 1);
        List<Device> list = null;
        try {
            list = EasyPoiUtil.importExcel(file.getInputStream(),params, Device.class);
            if (!CollectionUtils.isEmpty(list)) {
                for (Device device : list) {
                    log.info("device:{}", device);
                }
            }
        } catch (IOException e) {
            throw new ServiceException("导入excel异常",e);
        }
    }

    /**
     * 使用easypoi库按Sheet进行Excel文件导入
     *
     * @param file 上传的Excel文件
     */
    @Override
    public void impEasyPoiSheet(MultipartFile file) {
        try {
            final byte[] fileBytes = file.getBytes();
            final List<String> sheetNames = PoiUtils.getSheetNames(fileBytes);
            processSheets(fileBytes, sheetNames);
        } catch (IOException e) {
            throw new ServiceException("文件读取失败: " + e.getMessage(), e);
        } catch (Exception e) {
            throw new ServiceException("Excel处理异常: " + e.getMessage(), e);
        }
    }


    /**
     * 处理Excel文件中的所有Sheet
     *
     * @param fileBytes  文件内容的字节数组
     * @param sheetNames Sheet名称列表
     */
    private void processSheets(byte[] fileBytes, List<String> sheetNames) {
        for (int sheetIndex = 0; sheetIndex < sheetNames.size(); sheetIndex++) {
            final String sheetName = sheetNames.get(sheetIndex);
            final Class<?> targetClass = matchTargetClass(sheetName);
            if (targetClass == null) {
                log.warn("跳过未配置的Sheet: {}", sheetName);
                continue;
            }
            processSingleSheet(fileBytes, sheetIndex, sheetName, targetClass);
        }
    }

    /**
     * 根据Sheet名称匹配对应的数据模型类
     *
     * @param sheetName Sheet名称
     * @return 对应的数据模型类，如果Sheet名称未配置则返回null
     */
    private Class<?> matchTargetClass(String sheetName) {
        switch (sheetName) {
            case "设备信息":
                return Device.class;
            case "使用记录":
                return UserRecord.class;
            default:
                return null;
        }
    }

    /**
     * 处理单个Sheet的数据
     *
     * @param fileBytes   文件内容的字节数组
     * @param sheetIndex  Sheet索引
     * @param sheetName   Sheet名称
     * @param targetClass 对应的数据模型类
     */
    private void processSingleSheet(byte[] fileBytes, int sheetIndex, String sheetName, Class<?> targetClass) {
        try (ByteArrayInputStream bis = new ByteArrayInputStream(fileBytes)) {
            ImportParams params = createImportParams(sheetIndex);
            List<?> dataList = ExcelImportUtil.importExcel(bis, targetClass, params);
            if (!CollectionUtils.isEmpty(dataList)) {
                log.info("成功解析 Sheet[{}] 数据 {} 条", sheetName, dataList.size());
                dataList.forEach(data -> log.info("详细数据: {}", data));
            }
        } catch (Exception e) {
            log.error("Sheet[{}] 解析失败: {}", sheetName, e.getMessage());
            throw new ServiceException("Sheet[" + sheetName + "] 解析异常", e);
        }
    }

    /**
     * 创建导入参数对象
     *
     * @param sheetIndex Sheet索引
     * @return ImportParams对象，用于配置Sheet的导入参数
     */
    private ImportParams createImportParams(int sheetIndex) {
        ImportParams params = new ImportParams();
        params.setStartSheetIndex(sheetIndex);
        params.setTitleRows(1);
        params.setHeadRows(1);
        return params;
    }

    @Override
    public void impEasyPoiAlikeSheet(MultipartFile file) {

    }
}
